import java.util.Comparator;

public class Term implements ITerm {

    // instance variables
    private String term;
    private long weight;

    /**
     * init term with given query and weight
     *
     * @param term   query string
     * @param weight weight
     * @throws IllegalArgumentException if term is null or weight is negative
     */
    public Term(String term, long weight) {
        if (term == null) {
            throw new IllegalArgumentException("query string cannot be null");
        }
        if (weight < 0) {
            throw new IllegalArgumentException("weight cannot be negative");
        }
        this.term = term;
        this.weight = weight;
    }

    /**
     * compare two terms by weight, bigger first
     *
     * @return comparator
     */
    public static Comparator<ITerm> byReverseWeightOrder() {
        return (term1, term2) -> Long.compare(term2.getWeight(), term1.getWeight());
    }

    /**
     * compare two queries using just the first r letters in lex order
     *
     * @param r number of letters to use
     * @return comparator
     * @throws IllegalArgumentException if r is negative
     */
    public static Comparator<ITerm> byPrefixOrder(int r) {
        if (r < 0) {
            throw new IllegalArgumentException("r cannot be negative");
        }

        return (term1, term2) -> {
            String s1 = term1.getTerm();
            String s2 = term2.getTerm();

            // get first r letters or whole string if shorter
            String prefix1 = s1.length() < r ? s1 : s1.substring(0, r);
            String prefix2 = s2.length() < r ? s2 : s2.substring(0, r);

            return prefix1.compareTo(prefix2);
        };
    }

    /**
     * compare queries lexicographically
     */
    @Override
    public int compareTo(ITerm that) {
        return this.term.compareTo(that.getTerm());
    }

    /**
     * return string: weight, then a tab, then query
     */
    @Override
    public String toString() {
        return weight + "\t" + term;
    }

    /**
     * get term weight
     */
    @Override
    public long getWeight() {
        return weight;
    }

    /**
     * get term query
     */
    @Override
    public String getTerm() {
        return term;
    }

    /**
     * set term weight
     */
    @Override
    public void setWeight(long weight) {
        if (weight < 0) {
            throw new IllegalArgumentException("weight cannot be negative");
        }
        this.weight = weight;
    }

    /**
     * set term query and return it
     *
     * @return set query string
     */
    @Override
    public String setTerm(String term) {
        if (term == null) {
            throw new IllegalArgumentException("query string cannot be null");
        }
        this.term = term;
        return this.term;
    }
}
